package com.lsp.microorder.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.lsp.microcommon.entity.DropOrder;
import com.lsp.microcommon.entity.RechargeInfo;
import com.lsp.microorder.pay.dao.DropOrderDao;
import com.lsp.microorder.pay.param.PayParam;
import com.lsp.microorder.pay.param.PayResultParam;
import com.lsp.microorder.pay.param.TradePayParam;
import com.lsp.microorder.pay.service.PayService;
import com.lsp.microorder.pay.service.TradeOrderPayService;
import com.lsp.microorder.pay.vo.PayH5Vo;
import com.lsp.microorder.recharge.service.RechargeInfoService;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

@Service
public class TradeOrderPayServiceImpl implements TradeOrderPayService {

    @Resource(name = "aliPayServiceImpl")
    private PayService aliPayService;

    @Resource(name = "wxH5PayServiceImpl")
    private PayService wxNativePayService;

    @Resource
    private RechargeInfoService rechargeInfoService;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private DropOrderDao dropOrderDao;

    @Resource
    private RabbitTemplate rabbitTemplate;
    @Override
    public PayH5Vo tradeOrderPay(TradePayParam param) {
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
//        String tradeNo = UUID.randomUUID().toString().replace("-", "");

        RechargeInfo rechargeInfo = rechargeInfoService.rechargeInfo(param.getOrderId());
        if (rechargeInfo == null) {
            throw new RuntimeException("充值订单信息不存在");
        }
//        支付状态一般使用枚举，1未支付，
        if (!rechargeInfo.getStateFlag().equals(1)) {
            throw new RuntimeException("该订单不是待支付状态");
        }
        PayParam payParam = new PayParam();
        payParam.setTradeNo(rechargeInfo.getOrderNo());
        //        支付金额查数据库，或者直接在前端传到后端订单信息
//                      测试状态下，金额写死
//                 正常业务中，针对前端传来的金额，需要跟后端订单数据中的金额进行比对
//                    针对使用优惠券或者积分的情况，需要在后端重新计算金额
        payParam.setTotalAmount(new BigDecimal("0.01"));
        payParam.setSubject("会员充值");
        PayH5Vo payH5Vo = new PayH5Vo();
        payH5Vo.setOrderNo(rechargeInfo.getOrderNo());
        if (param.getPayType().equals(2)) {
//            支付宝支付
            payH5Vo.setH5PayUrl(aliPayService.createPayOrder(payParam));
        } else if (param.getPayType().equals(1)) {
//            微信支付
            payH5Vo.setH5PayUrl(wxNativePayService.createPayOrder(payParam));
        }
//        向掉单表中添加数据
//        掉单表是进行掉单处理的，防止有些信球支付一半不支付了，或者是优惠网络波动原因，并未收到支付宝系统的回调信息
//        DropOrder dropOrder = new DropOrder();
//        dropOrder.setOrderNo(rechargeInfo.getOrderNo());
//        dropOrder.setPayType(param.getPayType());
//        dropOrderDao.insert(dropOrder);

        DropOrder dropOrder = new DropOrder();
        dropOrder.setOrderNo(rechargeInfo.getOrderNo());
        dropOrder.setPayType(param.getPayType());
        dropOrder.setNum(0);
//        将掉单信息写入消息队列
        sendDropDelayMsg(dropOrder);
        return payH5Vo;
    }

    @Override
    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
//        在回调路径中增加了特定参数
//          如果是支付宝的话，可以获取到路径中的参数
//          如果是微信，无法通过如下方式获得数据
        String orderNo = request.getParameter("orderNo");
        if (StringUtils.isNoneBlank(orderNo)) {
            aliPayService.notify(request, response, payResultParam -> payFinish(payResultParam));
        } else {
            wxNativePayService.notify(request, response, payResultParam -> payFinish(payResultParam));
        }
    }

//  订单完成后，根据orderId修改数据库的订单状态和交易订单号
    @Override
    public void payFinish(PayResultParam param) {
//        判断支付状态，未支付情况下才会做相关操作
//          针对集群部署，一般需要加分布式锁
        RLock lock = redissonClient.getLock("payLock:" + param.getOrderNo());
        try {
            if (lock.tryLock(0, 10, TimeUnit.SECONDS)) {
                RechargeInfo rechargeInfo = rechargeInfoService.selectInfoByOrderId(param.getOrderNo());
                if (rechargeInfo != null && rechargeInfo.getStateFlag().equals(1)) {
                    rechargeInfoService.updateRechargeInfo(param);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isLocked()) {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }

    @Override
    public void payReturnUrl(HttpServletRequest request, HttpServletResponse response) {
        aliPayService.returnNotify(request, response);
    }

    @Override
    public String payStates(String orderNo, Integer payType) {
        if (payType.equals(2)) {
            return aliPayService.payStates(orderNo);
        } else {
            return wxNativePayService.payStates(orderNo);
        }
    }

    @Override
    public void closePay(String orderNo, Integer payType) {
        if (payType.equals(2)) {
            aliPayService.closePay(orderNo);
        } else {
            wxNativePayService.closePay(orderNo);
        }
    }

    @Override
    public void sendDropDelayMsg(DropOrder dropOrder) {
        String msg = JSON.toJSONString(dropOrder);
//        向普通的订单交换机发送消息
        rabbitTemplate.convertAndSend("drop_order_delay_ex",
                "drop_order_delay_key",
                msg,
                new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置过期时间30s
                message.getMessageProperties().setDelay(10000);
                return message;
            }
        });
    }
}
